import React, { Component } from 'react';
import PropTypes from 'prop-types';
import zipObject from 'lodash/zipObject';
import { injectReducer } from './asyncReducers';

export default function asyncComponent(importComponent, reducerOpts = {}) {

  let getComponent = null;
  let reducerKeys = Object.keys(reducerOpts);

  if (typeof importComponent === 'function') {
    getComponent = importComponent;
  }

  class AsyncComponent extends Component {

    static contextTypes = {
      store: PropTypes.shape({
        replaceReducer: PropTypes.func.isRequired,
      }),
    };

    static Component = null;

    static reducers = {};

    static loadComponentAndReducers() {
      return Promise.resolve()
        .then(() => {
          if (reducerKeys && reducerKeys.length) {
            const reducerPromises = reducerKeys.map(key => reducerOpts[key]());

            return Promise.all(reducerPromises)
              .then(reducerMods => {
                return reducerMods.map(m => m.reducer || m.default);
              })
              .then(reducerFuncs => {
                AsyncComponent.reducers = zipObject(reducerKeys, reducerFuncs);
              });
          }
        })
        .then(() => getComponent())
        .then(m => m.default)
        .then(Component => {
          AsyncComponent.Component = Component;
          // hoistNonReactStatics(AsyncComponent, Component);
          return Component;
        });
    }

    constructor(props) {
      super(props);
      this.state = {
        component: null
      }
    }

    // async componentDidMount() {
    //   const { default: component } = await importComponent();
    //   this.setState({
    //     component
    //   });
    // }
    
    componentDidMount() {
      if (getComponent) {
        AsyncComponent.loadComponentAndReducers()
        .then(Component => {
          injectReducer(this.context.store, AsyncComponent.reducers);
          this.setState({
            component: Component
          });
        });
        // getComponent().then(({default: component}) => {
        //   this.setState({
        //     component 
        //   });
        // });
      }
    }

    render() {
      const { component: C } = this.state;
      return (
        C ? <C {...this.props}/> : null
      );
    }
  }

  return AsyncComponent;
}